package Sonnet;

import java.awt.Dimension;

import javafx.application.Application;

import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.Scene;
import javafx.stage.Stage;

import javafx.fxml.FXMLLoader;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.scene.SnapshotParameters;

import java.awt.*;
import java.awt.image.*;
import java.awt.event.ActionEvent;
import java.awt.Dimension;
import java.lang.Object;
import java.io.InputStream;
import java.io.File;
import javax.imageio.ImageIO;//Keep For .png Image Creation
import java.io.IOException;
import java.nio.ByteBuffer;

import javafx.scene.paint.Color;
import javafx.geometry.Rectangle2D;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.image.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritableImage.*;
import javafx.scene.input.KeyEvent;
//import javafx.scene.layout.VBox;
import javafx.scene.text.*;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.scene.layout.*;
//import javafx.scene.paint.Color;
//import javafx.scene.shape.*;

//import java.util.Timer;
//import java.util.TimerTask;
import javax.swing.JFileChooser;
//import javafx.stage.DirectoryChooser;
//import javafx.stage.FileChooser;
import javafx.embed.swing.SwingFXUtils;
import org.jcodec.api.awt.SequenceEncoder;//Keep For .mp4 Video Creation

public class Sonnet extends Application
{

	@Override
	public void start(Stage stage) throws IOException
	{
		Thread thread = new Thread(() -> {
			try { Thread.sleep(400); }
			catch (InterruptedException exc) { throw new Error("Unexpected interruption", exc); }
			// Update text on FX Application Thread:
			Platform.runLater(new Runnable() {
				@Override
				public void run()
				{
					try { RainbowSystem(stage); }
					catch(IOException ie) { ie.printStackTrace(); }
				}
			});
		});
		thread.setDaemon(true);
		thread.start();
	}
	
	static void RainbowSystem(Stage primaryStage) throws IOException
	{
		primaryStage.setTitle("Sonnet");
		primaryStage.setWidth(1920);
		primaryStage.setHeight(1080);

		// This is how you know how much screen you can write to.
		Screen screen = Screen.getPrimary();
		Rectangle2D bounds = screen.getVisualBounds();
		System.out.println(bounds);

		primaryStage.setFullScreen(true);
		
		double fRateDivisor = 22;//444 HERE HERE HERE DETERMINES FRAME RATE AND RAINBOW MOVEMENT RATE

		FXMLLoader loader = new FXMLLoader(Sonnet.class.getResource("main.fxml"));
		
		
		StackPane stackPane[] = new StackPane[(int)(fRateDivisor + 1)];
		stackPane[0] = new StackPane();
		stackPane[0].setPrefSize(1920, 1080);//stackPane.setPrefSize(1920, 1080);//stackPane.setPrefSize(960, 540);

		Dimension dimension = new Dimension( (int)bounds.getWidth(), (int)bounds.getHeight() );
		dimension.width = (int)bounds.getWidth();
		dimension.height = (int)bounds.getHeight() + 40;
		Dimension Dim = dimension;
		
		//Image image = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");
		
		WebView browser = new WebView();
		WebEngine webEngine = browser.getEngine();
		webEngine.load("http://www.pixies.zone/PixiesTest.html");
		SnapshotParameters sP = new SnapshotParameters();
		sP.setViewport(bounds);
		
		WritableImage origionalTextPicture = new WritableImage( dimension.width, dimension.height );
		//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
		//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Test.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
		Image origionalBrowserImage = browser.snapshot(sP, origionalTextPicture);
		PixelReader origionalpr = origionalBrowserImage.getPixelReader();
		PixelWriter origionalpw = origionalTextPicture.getPixelWriter();
		ImageView origionalImageView = new ImageView();
		origionalImageView.setImage(origionalBrowserImage);
		
		JFileChooser jFileChooser = new JFileChooser();
		String path = "C:\\TestVideo.mp4", text = "Sky.Netarianism";//"C:\\TestImage.png"//"C:\\TestVideo.mp4"//"C:\\TEMP_Sonnet.mp4";
		File selectedFile = new File (path);
		
		jFileChooser.setSelectedFile(selectedFile);
		int returnValue = jFileChooser.showSaveDialog(null);
		if (returnValue == JFileChooser.APPROVE_OPTION)
		{
			selectedFile = jFileChooser.getSelectedFile();
			System.out.println(selectedFile.getName());
			System.out.println(selectedFile.getPath());
		}
		
		SequenceEncoder enc = new SequenceEncoder(selectedFile);

		Scene scene[] = new Scene[(int)(fRateDivisor + 1)];
		scene[0] = new Scene(stackPane[0]);
		
		//scene[0].setRoot(browser);
		
		stackPane[0].getChildren().add(origionalImageView);
		stackPane[0].getChildren().add(browser);
		primaryStage.setScene(scene[0]);
		
		primaryStage.setFullScreen(true);
		primaryStage.show();
		
		scene[0].snapshot(origionalTextPicture);
		
		WritableImage writableImage = origionalTextPicture;
		PixelReader pr = writableImage.getPixelReader();
		PixelWriter pw = writableImage.getPixelWriter();
		ImageView imageView = new ImageView();
		imageView.setImage(writableImage);
		
		
		
		
		
		
		

		
		
		

		


		//*/
				double xSlider = 0;
				//try {// new Timer().schedule(new TimerTask() { public void run() {
				ColorSlider black = new ColorSlider( new double[]{0,0,0} );

				ColorSlider color = black;

				ColorSlider white = new ColorSlider( new double[]{255,255,255} );
				ColorSlider skyblue = new ColorSlider( new double[]{134,206,249} );
				ColorSlider pink = new ColorSlider( new double[]{255,64,143} );
				ColorSlider blue = new ColorSlider( new double[]{0,0,192} );
				ColorSlider red = new ColorSlider( new double[]{193,0,0} );
				ColorSlider purple = new ColorSlider( new double[]{122,0,178} );
				ColorSlider orange = new ColorSlider( new double[]{255,134,0} );
				ColorSlider green = new ColorSlider( new double[]{0,133,50} );
				ColorSlider yellow = new ColorSlider( new double[]{246,252,15} );
				ColorSlider teal = new ColorSlider( new double[]{3,224,149} );
				ColorSlider bronze = new ColorSlider( new double[]{152,123,46} );
				ColorSlider silver = new ColorSlider( new double[]{193,192,192} );
				ColorSlider gold = new ColorSlider( new double[]{205,191,44} );
				ColorSlider lime = new ColorSlider( new double[]{126,193,33} );
				ColorSlider brown = new ColorSlider( new double[]{131,103,71} );

				int pixiePink = (int)(255 * 16777216) + (int)(255 * 65536) + (int)(0 * 256) + 255;

				int numberOfColorsInTheRainbow = 7;//asdf Always Worry About This!

				//int [] background = {255, 255, 255};
				//background = new int[Dim.width * Dim.height * 3];
				Dimension HalfedDim = new Dimension(Dim.width / 2, Dim.height / 2);
				//HalfedDim.width = Math.round( Dim.width / 2 );
				//HalfedDim.height = Math.round( Dim.height / 2 );
				double radialDistance = Math.pow(Math.pow(HalfedDim.width + 1, 2) + Math.pow(HalfedDim.height + 1, 2), 0.5);//For Clock And Rainbow Spiral No Whole Thing / 12 That Is For Fractal.
				//double radialVariableDistance = radialDistance;
				double fullAngle = Math.PI * radialDistance;
				double angle = 0;
				double a = 0;
				double radius = 0;
				double colorDisplacement = 0;

				double interval = fullAngle / 2 / fRateDivisor;//Last Division Determines The Frame Rate

				double colorInterval = fullAngle / ( numberOfColorsInTheRainbow - 1 );//For Rainbow Clock And Spiral
				//System.out.println(prWaterMark.getArgb(0, 0));
				while (xSlider < fullAngle / 10 )
				{
					for (int x = 0; x < Dim.width; x++)//x < HalfedDim.width * 2//For old Background Raster ( HalfedDim.width * 2 )// For Fractals And Rainbow Sliders And ??? ///To Test Moving Rainbow From Left To Right
					{
						for (int y = 0; y < Dim.height; y++)//y < HalfedDim.height * 2//For old Background Raster ( HalfedDim.height * 2 )//Comment Out Here For NonFractals
						{
							//radialVariableDistance = Math.pow(Math.pow(x - HalfedDim.width + 1, 2) + Math.pow( y - HalfedDim.height + 1, 2), 0.5);//Comment Out For  Ghetto Many Rainbow Clocks 

							/*if ( y - HalfedDim.height + 1 != 0) //y - HalfedDim.height + 1 < -tolerance || y - HalfedDim.height + 1 > tolerance )// OLD: ( y - HalfedDim.height + 1) != 0 && y != 0 //Use For Old Infinite Number Theorem Down
								angle = Math.atan2( (x - HalfedDim.width + 1) , (y - HalfedDim.height + 1 ) );
							else
								angle = Math.atan2( (x - HalfedDim.width + 1), 0.0002 );// Uncomment For NonRising Sun*/
							angle = Math.atan2( (x - HalfedDim.width + 1) , (y - Dim.height * 4 / 3 + 1 ) );// For Rising Sun + 1
							//	angle = Math.atan( x - HalfedDim.width + 1 / ( y - HalfedDim.height + 1 ) );//WON'T WORK FOR NO GOOD REASON
							//else//WON'T WORK FOR NO GOOD REASON
							//	angle = Math.atan( x - HalfedDim.width + 1 / .0002 );//WON'T WORK FOR NO GOOD REASONRenderedImage
							//	angle = Math.atan2( x - HalfedDim.width + 1, tolerance ); //Adjust The Small Number For Mostly Black Screen

							a = ( angle * /*Math.cos( angle ) * Math.sin( angle ) * Math.pow(radialVariableDistance, 1)*/ Math.tan( angle ) /*+ Math.PI*/ )  * radialDistance / 4.46783504 + xSlider;// + Or - xSlider Determines Which Direction It Moves //For Infinite Number Theorem Good a = ( angle * /*Math.cos( angle ) * Math.sin( angle ) * Math.pow(radialVariableDistance, 1)*/ Math.tan( angle ) + Math.PI )  * radialDistance / 4.46783504 - xSlider;  //a = ( angle /*Math.cos( angle ) * Math.sin( angle ) * Math.pow(radialVariableDistance, 1)*/ Math.tan( angle ) + Math.PI )  * radialDistance / 4.46783504 - xSlider;//Use For Rainbow Spiral Multiply radialDistance By 10 To Increase The Number Of Spirals //Use This: "a = ( - angle + Math.PI ) * radialDistance;" Line For Rainbow Clock //a = ( - angle * Math.tan( angle ) + Math.PI ) * radialDistance - xSlider; For Infinite Number Theorem //a = ( - angle * Math.cos( angle ) * Math.sin( angle ) * Math.pow(radialVariableDistance, 2) + Math.PI ) * radialDistance - xSlider; */
							radius = a * 10;
							// *///For Old Infinite Number Theorem Use Above
							//radius = a * 10;//For Rainbow Spiral And Clock
							//}
							while ( radius < colorDisplacement)//For Rainbow Ring
								radius = radius + fullAngle - colorDisplacement;//BAD COMMENT: For Rainbow Ring Take Out - 38
							while ( radius > fullAngle )//radius > fullAngle For Non Infinite Number Theorem
								radius = radius - fullAngle - colorDisplacement; //radius = radius - fullAngle; For Non Infinite Number Theorem //For Rainbow Clock Comment Out To Here. Here -- */
							if ( radius >= colorDisplacement && radius < (numberOfColorsInTheRainbow - 1) * colorInterval  + colorDisplacement)//For Purple Outside Ring
							{
								if ( origionalpr.getArgb(x, y) == pixiePink )
									if ( radius < colorInterval  + colorDisplacement)//For Normal Rainbow Use This Instead Of The Others
										color.ColorSliderFunction(colorInterval, radius - colorDisplacement, purple, blue);
									else if ( radius < ( 2 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - colorInterval - colorDisplacement, blue, teal);
									else if ( radius < ( 3 * colorInterval  + colorDisplacement) )		
										color.ColorSliderFunction(colorInterval, radius - 2 * colorInterval - colorDisplacement, teal, pink);
									else if ( radius < ( 4 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - 3 * colorInterval - colorDisplacement, pink, yellow);
									else if ( radius < ( 5 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - 4 * colorInterval - colorDisplacement, yellow, orange);
									else
										color.ColorSliderFunction(colorInterval, radius - 5 * colorInterval - colorDisplacement, orange, red);
								else
									if ( radius < colorInterval  + colorDisplacement)//For Normal Rainbow Use This Instead Of The Others
										color.ColorSliderFunction(colorInterval, radius - colorDisplacement, red, orange);
									else if ( radius < ( 2 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - colorInterval - colorDisplacement, orange, yellow);
									else if ( radius < ( 3 * colorInterval  + colorDisplacement) )		
										color.ColorSliderFunction(colorInterval, radius - 2 * colorInterval - colorDisplacement, yellow, green);
									else if ( radius < ( 4 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - 3 * colorInterval - colorDisplacement, green, teal);
									else if ( radius < ( 5 * colorInterval  + colorDisplacement) )
										color.ColorSliderFunction(colorInterval, radius - 4 * colorInterval - colorDisplacement, teal, blue);
									else
										color.ColorSliderFunction(colorInterval, radius - 5 * colorInterval - colorDisplacement, blue, purple);
								
								/*if ( radius < colorInterval  + colorDisplacement)//For Normal Rainbow Use This Instead Of The Others
									color.ColorSliderFunction(colorInterval, radius - colorDisplacement, white, skyblue);
								else if ( radius < ( 2 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - colorInterval - colorDisplacement, skyblue, pink);
								else if ( radius < ( 3 * colorInterval  + colorDisplacement) )		
									color.ColorSliderFunction(colorInterval, radius - 2 * colorInterval - colorDisplacement, pink, blue);
								else if ( radius < ( 4 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 3 * colorInterval - colorDisplacement, blue, red);
								else if ( radius < ( 5 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 4 * colorInterval - colorDisplacement, red, purple);
								else if ( radius < ( 6 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 5 * colorInterval - colorDisplacement, purple, orange);
								else if ( radius < ( 7 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 6 * colorInterval - colorDisplacement, orange, green);
								else if ( radius < ( 8 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 7 * colorInterval - colorDisplacement, green, yellow);
								else if ( radius < ( 9 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 8 * colorInterval - colorDisplacement, yellow, teal);
								else if ( radius < ( 10 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 9 * colorInterval - colorDisplacement, teal, bronze);
								else if ( radius < ( 11 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 10 * colorInterval - colorDisplacement, bronze, silver);
								else if ( radius < ( 12 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 11 * colorInterval - colorDisplacement, silver, gold);
								else if ( radius < ( 13 * colorInterval  + colorDisplacement) )
									color.ColorSliderFunction(colorInterval, radius - 12 * colorInterval - colorDisplacement, gold, lime);
								else
									color.ColorSliderFunction(colorInterval, radius - 13 * colorInterval - colorDisplacement, lime, brown);//*/

							}
							//background[3 * x + Dim.width * 3 * y + 0] = (int)color.RGB[0];//background[3 * x + (HalfedDim.width * 6 + 3) * y + 0]
							//background[3 * x + Dim.width * 3 * y + 1] = (int)color.RGB[1];//background[3 * x + (HalfedDim.width * 6 + 3) * y + 1]
							//background[3 * x + Dim.width * 3 * y + 2] = (int)color.RGB[2];//background[3 * x + (HalfedDim.width * 6 + 3) * y + 2]//*/
							pw.setArgb( x, y, (int)(255 * 16777216 + (int)color.RGB[0] * 65536 + (int)color.RGB[1] * 256 + (int)color.RGB[2]));//setArgb
						}
					}
					
					imageView.setImage(writableImage);
					
					stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1] = new StackPane();
					stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1].getChildren().add(imageView);
					scene[(int)(fRateDivisor * xSlider/fullAngle) + 1] = new Scene(stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1]);
					primaryStage.setScene(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1]);

					System.out.println(Dim);

					primaryStage.setFullScreen(true);

					primaryStage.show();
					
					if (xSlider == 0)
					{
						File outputFile = new File("C:/TestImage.png");
					    BufferedImage bImage = SwingFXUtils.fromFXImage(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1].snapshot(null), null);
					    try {
					      ImageIO.write(bImage, "png", outputFile);
					    } catch (IOException e) {
					      throw new RuntimeException(e);
					    }
					}
				    enc.encodeImage( SwingFXUtils.fromFXImage(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1].snapshot(null), null ) );
				    //enc.encodeImage( SwingFXUtils.fromFXImage( imageView.getImage(), null ) );
					
					
					xSlider = xSlider + interval;
					System.out.println(Dim);
					//}
					//Thread.sleep(2000);}
					//catch (Exception ex) {ex.printStackTrace();}

				}
				enc.finish();
		
		
		
		
		
		
		
		
		
		
		
		
		
		System.out.println("Done Making Video");

		/*scene.setOnKeyReleased(new EventHandler<KeyEvent>()
		{
			@Override
			public void handle(KeyEvent event)
			{
				if ( event.isAltDown() == true)
				{
					switch (event.getCode())
					{
						case ENTER: primaryStage.setFullScreen(!primaryStage.isFullScreen()); break;
					}
				}
			}
		});//*/
	}
	
	public static void main(String[] args) throws IOException
	{
		launch(args);
	}
}